// run: $exec < input
// opt: 0
// flag: -g
#include <cstdio>
#include <cassert>
#include <algorithm>
#include <iostream>

int const maxn = 300007;

//#define PRINT_SPLAY
#define __DEBUG

struct node
{
	void update() { maxv = std::max(value, std::max(child[0]->maxv, child[1]->maxv)); }
	bool is_right() { return this == path_parent->child[1]; }
	void self_rev() { rev ^= true; std::swap(child[0], child[1]); }
	void set_child(node * c, int ir) { child[ir] = c; c->path_parent = this; }
	void set_root(node *);

	int value, maxv, delta;
	bool rev, is_root;
	node * parent, * child[2], * path_parent;
} memory[maxn],  * nil = memory;

void node::set_root(node * c) { parent = c; is_root = true; path_parent = nil; }

void inc(node * x, int d)
{
	if (x == nil) return;
	x->delta += d;  x->value += d;  x->maxv += d;
}

void push_down(node * t)
{
	if (t == nil) return;
	if (t->delta) {
		int d = t->delta;
		inc(t->child[0], d);
		inc(t->child[1], d);
		t->delta = 0;
	}
	if (t->rev) {
		for (int i = 0; i < 2; i++)
			if (t->child[i] != nil)
				t->child[i]->self_rev();
		t->rev = false;
	}
}

void rot(node * t)
{
#ifdef PRINT_SPLAY
	std::cerr << "    rot: " << t - memory << '\n';
#endif

	node * p = t->path_parent;
	push_down(p); push_down(t);
	bool ir = t->is_right();
	p->path_parent->set_child(t, p->is_right());
	p->set_child(t->child[!ir], ir);
	t->set_child(p, !ir);
	p->update();
	if (p->is_root) {
		p->is_root = false;
		t->is_root = true;
		t->parent = p->parent;
	}
}

void push_to(node * t) {
	static node * stk[maxn];
	int top = 0;
	while (t != nil) {
		//std::cerr << "fuck-> " << t - memory << '\n';
		stk[top++] = t;
		t = t->path_parent;
	}
	for (int i = top - 1; i >= 0; --i)
		push_down(stk[i]);
}

void print();

void splay(node * t, node * f = nil)
{
#ifdef PRINT_SPLAY
	std::cerr << "  splay: " << t - memory << '\n';
#endif
//	push_to(t);
	for (; t->path_parent != f; ) {
		std::cout << "node= " << t - memory << "--------------------" << std::endl;
		print();
	//	std::cout << "rot at= " << t - memory << '\n';
		if (t->path_parent->path_parent == f)
			rot(t);
		else
			t->is_right() == t->path_parent->is_right() ? (rot(t->path_parent), rot(t)) : (rot(t), rot(t));
	}
	t->update();
}

node * access(node * t)
{
#ifdef PRINT_SPLAY
	std::cerr << "access: " << t - memory << '\n';
#endif

	node * v = nil;
	for (; t != nil; v = t, t = t->parent) {
		splay(t);
		std::cout << "access at= " << t - memory << "--------" << std::endl;
		print();
		t->child[1]->set_root(t);
		t->set_child(v, 1);
		v->parent = t;
	}
	return v;
}

node * get_root(node * t)
{
	//std::cerr << "get root: " << t - memory << '\n';

	for (access(t), splay(t); t->child[0] != nil; t = t->child[0]);
	//std::cerr << "root is:  " << t - memory << '\n';
	return t;
}

void make_root(node * u)
{
	access(u)->self_rev();
	splay(u);
}

void link(node * u, node * v)
{
	make_root(u);
	u->parent = v;
}

void cut(node * u, node * v)
{
	make_root(u);
	access(v);
	splay(u);
	u->set_child(nil, 1);
	u->update();
	v->parent = nil;
	v->is_root = true;
	v->path_parent = nil;
}

void add(node * u, node * v, int d)
{
	make_root(u);
	access(v);
	splay(v);
	inc(v, d);
}

int query_max(node * u, node * v)
{
	make_root(u);
	access(v);
	splay(v);
	return v->maxv;
}

int n, m;

void init()
{
	for (int i = 0; i <= n; i++) {
		node * node = memory + i;
		node->parent = node->path_parent = node->child[0] = node->child[1] = nil;
		node->delta = node->maxv = node->value = 0;
		node->rev = node->is_root = false;
	}
}

void print()
{

#ifdef __DEBUG
	std::cout << "--------------------" << '\n';
	for (int i = 1; i <= n; i++) {
		std::cout << "node= " << i << "  value= " << memory[i].value << "  max= " << memory[i].maxv << "  par= " << memory[i].parent - memory;
		std::cout << "  path par= " << memory[i].path_parent - memory << "  left= " << memory[i].child[0] - memory << "  right= " << memory[i].child[1] - memory << "  rev= " << memory[i].rev;
		std::cout << "  isRoot= " << memory[i].is_root << '\n';
	}
	std::cout << "--------------------" << '\n';
	std::cout << '\n';
#endif
}

int main()
{
	while (std::scanf("%d", &n) != EOF) {
		init();

		/*
		link(memory + 1, memory + 2);
		link(memory + 2, memory + 4);
		link(memory + 2, memory + 5);

			print();

		access(memory + 1);

			print();
		splay(memory + 1);
			print();

		link(memory + 1, memory + 3);
			print();
		return 0;
		*/
		for (int i = 1, x, y; i < n; i++) {
			std::scanf("%d %d", &x, &y);
			link(memory + x, memory + y);
		}

		std::printf("\n------------------------------------\n");
		for (int i = 1; i <= n; i++) {
			std::printf("%d= %d\n", i, int(get_root(memory + i) - memory)), print();
		}
		std::printf("\n------------------------------------\n");

		for (int i = 1, x; i <= n; i++) {
			std::scanf("%d", &x);
			node * node = memory + i;
			splay(node);
			node->value = node->maxv = x;
			node->update();
		}
		std::scanf("%d", &m);
		for (int i = 0, op, x, y, z; i < m; i++) {
			std::scanf("%d %d %d", &op, &x, &y);
			node * n1 = memory + x;
			node * n2 = memory + y;
			switch (op) {
				case 1:
					if (get_root(n1) == get_root(n2)) std::printf("-1\n");
					else link(n1, n2); break;
				case 2:
					if (n1 == n2 || get_root(n1) != get_root(n2)) std::printf("-1\n");
					else cut(n1, n2); break;
				case 3:
					z = x; std::scanf("%d", &x); n1 = memory + x;
					if (get_root(n1) != get_root(n2)) std::printf("-1\n");
					else add(n1, n2, z); break;
				case 4:
					if (get_root(n1) != get_root(n2)) std::printf("-1\n");
					else std::printf("%d\n", query_max(n1, n2));
			}
			//std::printf("--->%d %d %d\n", op, x, y);
		}
		return 0;
		std::printf("\n");
	}
}

